import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"

import { cn } from "@/utils/cn"
import { Button } from "./button"
import { Popover, PopoverContent, PopoverTrigger } from "./popover"

const Tabs = TabsPrimitive.Root

interface TabsListProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> {
  mode?: 'scroll' | 'dropdown'
}

const TabsList = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.List>,
  TabsListProps
>(({ className, mode = 'scroll', children, ...props }, ref) => {
  const listRef = React.useRef<HTMLDivElement>(null)
  const tabsRef = React.useRef<HTMLElement | null>(null)
  const [showControls, setShowControls] = React.useState(false)
  const [scrollPosition, setScrollPosition] = React.useState(0)
  const [maxScroll, setMaxScroll] = React.useState(0)
  const [overflowItems, setOverflowItems] = React.useState<React.ReactNode[]>([])
  const [visibleItems, setVisibleItems] = React.useState<React.ReactNode[]>([])
  
  // 存储每个tab元素的引用
  const tabRefs = React.useRef<Map<number, HTMLElement>>(new Map())
  
  const updateOverflow = React.useCallback(() => {
    if (!listRef.current) return
    const container = listRef.current
    const list = container.querySelector('[role="tablist"]') as HTMLElement
    if (!list) return
    
    tabsRef.current = list

    const containerWidth = container.offsetWidth
    const listWidth = list.scrollWidth
    const hasOverflow = listWidth > containerWidth

    // 只有在scroll模式下才显示控制按钮
    setShowControls(hasOverflow && mode === 'scroll')
    setMaxScroll(Math.max(0, listWidth - containerWidth))

    if (mode === 'dropdown' && hasOverflow) {
      const dropdownButtonWidth = 40 // 为下拉按钮预留的宽度
      const availableWidth = containerWidth - dropdownButtonWidth
      const visible: React.ReactNode[] = []
      const overflow: React.ReactNode[] = []
      
      let accumulatedWidth = 0
      
      // 使用实际DOM元素计算宽度
      React.Children.forEach(children, (child, index) => {
        if (!React.isValidElement(child)) return
        
        const tabElement = tabRefs.current.get(index)
        // 如果没有引用，使用估计值
        const tabWidth = tabElement ? tabElement.offsetWidth : 100
        
        if (accumulatedWidth + tabWidth <= availableWidth) {
          visible.push(child)
          accumulatedWidth += tabWidth
        } else {
          overflow.push(child)
        }
      })
      
      setVisibleItems(visible)
      setOverflowItems(overflow)
    } else {
      setVisibleItems(React.Children.toArray(children))
      setOverflowItems([])
    }
  }, [children, mode])

  // 当子元素挂载时获取它们的引用
  const setTabRef = React.useCallback((element: HTMLElement | null, index: number) => {
    if (element) {
      tabRefs.current.set(index, element)
    } else {
      tabRefs.current.delete(index)
    }
  }, [])

  // 包装每个子元素以获取引用
  const wrappedChildren = React.useMemo(() => {
    return React.Children.map(children, (child, index) => {
      if (!React.isValidElement(child)) return child
      
      // 使用DOM ref回调而不是直接设置ref属性
      return React.cloneElement(child, {
        // 使用安全的方式传递ref
        ...child.props,
        // @ts-ignore - 我们知道这是一个有效的属性，但TypeScript无法正确推断
        ref: (el: HTMLElement | null) => {
          setTabRef(el, index)
          // 保留原始ref
          const originalRef = (child as any).ref
          if (typeof originalRef === 'function') {
            originalRef(el)
          } else if (originalRef) {
            (originalRef as React.MutableRefObject<HTMLElement | null>).current = el
          }
        }
      })
    })
  }, [children, setTabRef])

  React.useEffect(() => {
    const resizeObserver = new ResizeObserver(() => {
      updateOverflow()
    })
    
    if (listRef.current) {
      resizeObserver.observe(listRef.current)
    }

    // 初始化后计算一次溢出状态
    setTimeout(() => {
      updateOverflow()
    }, 0)

    return () => resizeObserver.disconnect()
  }, [updateOverflow])
  
  // 监听滚动位置变化
  React.useEffect(() => {
    const handleScroll = () => {
      if (tabsRef.current) {
        setScrollPosition(tabsRef.current.scrollLeft)
      }
    }
    
    const tabsList = tabsRef.current
    if (tabsList) {
      tabsList.addEventListener('scroll', handleScroll)
      return () => tabsList.removeEventListener('scroll', handleScroll)
    }
  }, [])

  const scroll = (direction: 'left' | 'right') => {
    if (!listRef.current) return
    const list = listRef.current.querySelector('[role="tablist"]') as HTMLElement
    if (!list) return

    const scrollAmount = 200
    const newPosition = direction === 'left' 
      ? Math.max(0, scrollPosition - scrollAmount)
      : Math.min(maxScroll, scrollPosition + scrollAmount)

    list.scrollTo({ left: newPosition, behavior: 'smooth' })
    setScrollPosition(newPosition)
  }

  if (mode === 'dropdown') {
    return (
      <div ref={listRef} className={cn("relative flex items-center", className)}>
        <TabsPrimitive.List
          ref={ref}
          className="inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground overflow-hidden w-full"
          {...props}
        >
          {visibleItems}
          {overflowItems.length > 0 && (
            <Popover>
              <PopoverTrigger asChild>
                <Button
                  variant="ghost"
                  size="icon"
                  className="h-8 w-8 ml-1"
                >
                  <MoreHorizontal className="h-4 w-4" />
                </Button>
              </PopoverTrigger>
              <PopoverContent align="end" className="w-[200px] p-0">
                <div className="flex flex-col p-1 space-y-1">
                  {overflowItems}
                </div>
              </PopoverContent>
            </Popover>
          )}
        </TabsPrimitive.List>
      </div>
    )
  }

  return (
    <div ref={listRef} className={cn("relative flex items-center", className)}>
      {showControls && (
        <Button
          variant="ghost"
          size="icon"
          className={cn(
            "absolute left-0 z-10 h-8 w-8",
            scrollPosition <= 5 ? "opacity-0" : "opacity-100"
          )}
          onClick={() => scroll('left')}
        >
          <ChevronLeft className="h-4 w-4" />
        </Button>
      )}
      <TabsPrimitive.List
        ref={ref}
        className={cn(
          "inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
          showControls ? "mx-9 overflow-x-hidden" : "w-full"
        )}
        {...props}
      >
        {wrappedChildren}
      </TabsPrimitive.List>
      {showControls && (
        <Button
          variant="ghost"
          size="icon"
          className={cn(
            "absolute right-0 z-10 h-8 w-8",
            scrollPosition >= maxScroll - 5 ? "opacity-0" : "opacity-100"
          )}
          onClick={() => scroll('right')}
        >
          <ChevronRight className="h-4 w-4" />
        </Button>
      )}
    </div>
  )
})

TabsList.displayName = TabsPrimitive.List.displayName

const TabsTrigger = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.Trigger
    ref={ref}
    className={cn(
      "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow flex-1",
      className
    )}
    {...props}
  />
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName

const TabsContent = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.Content
    ref={ref}
    className={cn(
      "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
      className
    )}
    {...props}
  />
))
TabsContent.displayName = TabsPrimitive.Content.displayName

export { Tabs, TabsList, TabsTrigger, TabsContent }
